import json
import os
import time
import traceback
from datetime import datetime

from applications.configs.common import DRIVER_NAME_LIST
from applications.configs.func import aigc_func
from applications.extends.NovelSpider import BaseBook

from applications.extends.cacheUtils import Cache
from applications.models.novel import NovelMenu, NovelList, BookShelf, BookSource
from applications.models import Session
from sqlalchemy import and_

# 获取小说列表
def get_novel_list(user, private):
    # cache = Cache.getInstance()
    
    # 查询是否存在缓存
    # data = cache.get("novel_list")
    if True:
        # 获取缓存
        session = Session()
        try:
            data = (session.query(NovelList.id, NovelList.name, NovelList.update_status, NovelMenu.order, NovelMenu.name.label('chapter_name'))
            .outerjoin(BookShelf, and_(BookShelf.novel_id == NovelList.id, BookShelf.user_id == user.id, BookShelf.enable == 1))
            .outerjoin(NovelMenu, (BookShelf.chapter_id == NovelMenu.order) & (NovelMenu.novel_id == NovelList.id))
            .filter(NovelList.enable == 1, BookShelf.private == private).order_by(BookShelf.last_use.desc()))
            result = []
            # 输出
            # print(data.statement.compile(compile_kwargs={"literal_binds": True}))
            for i in data:
                # 获取最新章节
                last_chapter = session.query(NovelMenu).filter(NovelMenu.novel_id == i.id).order_by(NovelMenu.order.desc()).first()
                result.append({"update": i.update_status, "id": i.id, "name": i.name, "chapter_order": i.order, "chapter_name": i.chapter_name,
                            "last_order": last_chapter.order, "last_name": last_chapter.name})
            
            # 设置缓存
            # cache.set("novel_list", json.dumps(result, ensure_ascii=False), time=60 * 60 * 1)
            
        except Exception:
            print("获取小说列表异常", traceback.print_exc())
            return []
        finally:
            session.close()
    # else:
    #     result = json.loads(data) 
        
    return result


# 抓取小说列表
def grab_save_novels(user, data, tasks):
    session = Session()
    try:
        # 查询小说是否存在
        novel = session.query(NovelList).filter(NovelList.id == data.novel_id).first()
        if not novel:
            return False, "没有该书籍信息"
        
        # 更新状态
        if int(data.flg) == 1:
            if novel.update_status == 1:
                return False, "该书籍正在更新中"
        else:
            novel.update_status = 0
            session.commit()
            return True, "该书籍已停止更新"
        
        # 最新章节
        start_chapter = 1
        last_chapter = session.query(NovelMenu).filter(NovelMenu.novel_id == novel.id).order_by(NovelMenu.order.desc()).first()
        if last_chapter:
            start_chapter = last_chapter.order + 1
        # 结束页码
        end_chapter = start_chapter + 1000

    except Exception:
        print("抓取书籍列表异常", traceback.print_exc())
        return False, "抓取书籍列表异常"

    finally:
        session.close()

    # 后台添加章节信息
    tasks.add_task(addBookShelfTask, user=user, novel_id=novel.id, address=novel.address, start_chapter=start_chapter, end_chapter=end_chapter, add_book_shelf=False)

    return True, "操作成功"


# 缓存后10章的数据
def cache_book_content(novel_id, chapter):
    session = Session()
    cache = Cache.getInstance()
    try:
        contents = session.query(NovelMenu).filter(NovelMenu.novel_id == novel_id, NovelMenu.order >= chapter, NovelMenu.order <= int(chapter) + 10).all()
        # 删除缓存
        cache.delete("novel_list")

        for c in contents:
            # 查询是否存在缓存
            chapter_key = f"novel_content_{novel_id}_{c.order}"
            data = cache.get(chapter_key)
            if not data:
                # 获取缓存
                result = {"name": c.name, "drive": c.drive_name, "content": str(c.content).split("\n") if c else [], "order": c.order, "novel_id": novel_id}
                cache.set(chapter_key, json.dumps(result, ensure_ascii=False), time=60 * 10)

    except Exception:
        print("缓存内容章节异常", traceback.print_exc())
    finally:
        cache.quit_all()
        session.close()


# 查看数据内容
def get_content_data_func(user, data, tasks):
    session = Session()
    content = {}
    cache = Cache.getInstance()
    stask_novel_id = 0
    stask_chapter = 0
    try:
        # 修改书架状态
        user_book = session.query(BookShelf).filter(BookShelf.novel_id == data.novel_id, BookShelf.user_id == user.id).first()
        if user_book:
            update_data = {}
            # 状态更改
            if user_book.enable == 0:
                update_data["enable"] = 1
            # 章节不一致
            if data.chapter_id != user_book.chapter_id:
                update_data.update(chapter_id=data.chapter_id, last_use=datetime.now())

            # 修改记录
            if len(update_data) > 0:
                session.query(BookShelf).filter(
                    BookShelf.novel_id == data.novel_id, BookShelf.user_id == user.id
                ).update(update_data)
        else:
            book_shelf = BookShelf(**dict(data), enable=1, user_id=user.id, last_use=datetime.now())
            session.add(book_shelf)

        # 获取书籍内容
        chapter_key = "novel_content_" + str(data.novel_id) + "_" + str(data.chapter_id)
        result = cache.get(chapter_key)
        if not result:
            find_content = session.query(NovelMenu).filter(NovelMenu.novel_id == data.novel_id, NovelMenu.order == data.chapter_id).first()
            if not find_content:
                # 获取后一个章节
                find_content = session.query(NovelMenu).filter(NovelMenu.novel_id == data.novel_id, NovelMenu.order >= data.chapter_id).order_by(NovelMenu.order.asc()).first()
                if not find_content:
                    return False, "章节不存在"
            
            content["content"] = str(find_content.content).split("\n") if find_content else []
            content["name"] = find_content.name
            content["drive"] = find_content.drive_name
            content["order"] = find_content.order
            content["novel_id"] = find_content.novel_id

            stask_novel_id = data.novel_id
            stask_chapter = data.chapter_id
        else:
            content = json.loads(result)

        session.commit()
    except Exception:
        print("记录用户记录 异常", traceback.print_exc())
        session.rollback()

        return False, "记录异常"
    finally:
        cache.quit_all()
        session.close()

    # 后台添加10章的缓存数据
    if int(stask_novel_id) > 0:
        tasks.add_task(cache_book_content, novel_id=int(stask_novel_id), chapter=int(stask_chapter) + 1)
    for i in ['xs007.com', 'shuyue.net', 'dengbi.net', '————————————']:
        try:
            for c, v in enumerate(content["content"]):
                if i in c:
                    del content["content"][c]
        except:
            pass
    return True, content


# 在线搜索书籍
def inter_search_books_func(user, name, driver):
    """
        在线搜索书籍
    :param user:   用户
    :param name:   搜索名字
    :return:
    """
    if not driver:
        return False, "请选择驱动"
    
    if driver not in DRIVER_NAME_LIST:
        return False, "驱动异常"
    
    book = BaseBook(driver)
    return True, book.search_books(name)


def start_source_update_task_func(books=None):
    print("更新书籍书源 开始")
    session = Session()
    try:
        if not books:
            books = session.query(NovelList).filter(NovelList.enable == 1).all()
        for b in books:
            for drive_name in DRIVER_NAME_LIST:
                add_session = Session()
                # 查找是否存在书源
                book = add_session.query(BookSource).filter_by(novel_id=b.id, drive_name=drive_name).first()
                if not book:
                    drive_obj = BaseBook(drive_name)
                    try:
                        book_list = drive_obj.search_books(b.name)
                        book_source_list = [c for c in book_list if (c["name"] == b.name) and (c["author"] == b.author)]
                        address = book_source_list[0]["address"] if len(book_source_list) >= 1 else None

                        # 添加书源信息
                        enable = 1 if address else 0
                        book_source = BookSource(novel_id=b.id, drive_name=drive_name, name=b.name, author=b.author, address=address, enable=enable)
                        add_session.add(book_source)
                        add_session.commit()
                        msg = "成功"
                    except Exception:
                        msg = "异常"
                        drive_obj.browser.close()
                        print(f"驱动查询 {drive_name} 异常", traceback.format_exc())
                    finally:
                        add_session.close()
                    print("书籍：{} 驱动{} 书源查询完成：{}".format(b.name, drive_name, msg))
                else:
                    last_chapter = 0
                    # 地址为真，查询最新章节
                    if book.address:
                        drive_obj = BaseBook(drive_name)
                        try:
                            last_chapter = drive_obj.get_last_new_chapter(book.address)
                            # 更新最新章节
                            if int(last_chapter) > 0:
                                add_session.query(BookSource).filter_by(id=book.id).update({"chapter": last_chapter})
                                add_session.commit()

                        except Exception:
                            drive_obj.browser.close()
                            print(f"查询驱动最新章节 {drive_name} 异常", traceback.format_exc())
                        finally:
                            add_session.close()
                    print("书籍：{} 驱动{} 查询驱动最新章节完成：{}".format(b.name, drive_name, last_chapter))

                # 休息10秒
                time.sleep(2)
    except Exception:
        print("更新书籍书源 异常", traceback.format_exc())

    finally:
        session.close()
        print("更新书籍书源 完成")


# 添加书籍
def add_inter_books_func(user, data, tasks):
    """
        添加书籍
    :param user:   用户
    :param data:   添加书籍模型
    :return:
    """
    # 添加书籍
    session = Session()
    try:
        # 添加小说列表
        novel = session.query(NovelList).filter(NovelList.name == data.name, NovelList.author == data.author).first()
        if not novel:
            novel = NovelList(**dict(data), enable=1, update_status=0)
            session.add(novel)
            session.commit()
            session.refresh(novel)
            # 更新驱动源
            start_source_update_task_func([novel])

        else:
            # 查询是否存在章节
            if session.query(NovelMenu).filter(NovelMenu.novel_id == novel.id).first():
                return True, "该书籍已添加"

        # 开启异步任务
        tasks.add_task(addBookShelfTask, user=user, novel_id=novel.id, address=novel.address)

    except Exception:
        print("添加书籍异常", traceback.print_exc())
    finally:
        session.close()

    return True, "添加成功"


# 后台添加章节数据
def addBookShelfTask(user, novel_id, address, start_chapter=1, end_chapter=1, add_book_shelf=True):
    """
        添加书架任务
    :param user:            用户
    :param novel_id:        书籍id
    :param address:         书籍地址
    :param start_chapter:   开始章节
    :param end_chapter:     结束章节
    :param add_book_shelf:  是否添加书架
    :return:
    """
    # 修改小说为更新中
    session = Session()
    book = session.query(NovelList).filter(NovelList.id == novel_id).first()
    if book.update_status == 1:
        print("书籍: {}正在更新中".format(book.name))
        return True, "书籍正在更新中"
    book.update_status = 1
    session.commit()
    session.close()

    # 抓取章节
    try:
        # 取最后一章为驱动
        last_menu = session.query(NovelMenu).filter(NovelMenu.novel_id == novel_id).order_by(NovelMenu.order.desc()).first()
        if not last_menu or not last_menu.drive_name:
            print("没找到可更新的驱动")
            return False
        # 查询来源地址
        source = session.query(BookSource).filter(BookSource.drive_name == last_menu.drive_name, BookSource.novel_id == novel_id).first()
        driver_name = last_menu.drive_name
        address = source.address

        # 分段查询，加快速度 20 章查询一次
        old_start_chapter = 0
        for s in range(10):
            book = BaseBook(driver_name)
            start_chapter = start_chapter if s == 0 else start_chapter + 1
            new_end_chapter = start_chapter + 50
            contents = book.get_menu_content(address, start_chapter, new_end_chapter)
            for i in contents:
                session = Session()
                menu = None
                try:
                    if not session.query(NovelMenu).filter(NovelMenu.novel_id == novel_id, NovelMenu.order == i["chapter"]).first():
                        menu = NovelMenu(name=i["name"], order=i["chapter"], content=i["content"],
                                         drive_name=i["driver_name"], address=i["address"], novel_id=novel_id)
                        session.add(menu)
                        session.commit()
                    print("抓取 {} 成功".format(i["name"]))
                except:
                    print("抓取单页失败 ", traceback.print_exc())
                finally:
                    if start_chapter == 1:
                        if add_book_shelf and menu:
                            session.refresh(menu)

                            # 添加书架
                            session_z = Session()
                            session_z.add(BookShelf(user_id=user.id, novel_id=novel_id, chapter_id=menu.order))
                            session_z.commit()
                            session_z.close()
                            print("写入书架成功 ")

                    session.close()

                    start_chapter = start_chapter + 1
            print("分段抓取", address, old_start_chapter, start_chapter, new_end_chapter)
            if old_start_chapter != 0 and old_start_chapter + 1 >= start_chapter:
                print("没抓取到章节信息")
                break
            old_start_chapter = start_chapter
            # 抓取规定章节
            if end_chapter <= new_end_chapter:
                break

    except Exception:
        print("后台添加章节数据 异常", traceback.print_exc())
    finally:
        if not session.query(NovelMenu).filter(NovelMenu.novel_id == novel_id).first():
            # 添加章节
            menu = NovelMenu(name="抓取失败", order=1, content="抓取失败", drive_name="BQG", address="", novel_id=novel_id)
            session.add(menu)
            session.commit()
            # 添加书架
            session_z = Session()
            session_z.add(BookShelf(user_id=user.id, novel_id=novel_id, chapter_id=menu.order))
            session_z.commit()
            session_z.close()

        # 修改小说状态为更新成功
        session = Session()
        session.query(NovelList).filter(NovelList.id == novel_id).update({"update_status": 0})
        session.commit()
        session.close()


# 移除书架
def delete_book_shelf_func(user, data):
    session = Session()
    try:
        book = session.query(BookShelf).filter(BookShelf.novel_id==data.novel_id, BookShelf.user_id==user.id).first()
        if not book:
            return False, "该书籍不存在"
        # 移除书架
        session.query(BookShelf).filter(BookShelf.id == book.id).update({"enable": 0})
        # 书籍下架
        session.query(NovelList).filter(NovelList.id == book.id).update({"enable": 0})
        session.commit()

    except Exception:
        print("移除书架 异常", traceback.print_exc())
    finally:
        session.close()

    return True, "操作成功"


# 查看书源
def show_source(book_id, chapter_order):
    result = []
    now_source = ""
    session = Session()
    try:
        # 查询书源
        res = session.query(BookSource).filter_by(novel_id=book_id, enable=1).all()
        result = [{"id": i.id, "author": i.author, "drive_name": i.drive_name, "chapter": i.chapter} for i in res]

        # 当前源
        now_source = session.query(NovelMenu).filter_by(novel_id=book_id, order=chapter_order).first().drive_name
    except Exception:
        print("查看书源 异常", traceback.print_exc())
    finally:
        session.close()
    return result, now_source


# 异步切换书源
def sbsf(novel_id, drive_name, address, start_chapter):
    try:
        # 抓取章节信息
        book = BaseBook(drive_name)
        contents = book.get_menu_content(address, start_chapter, int(start_chapter) + 10)
        for c in contents:
            # print("抓取信息", c["chapter"], c["name"])
            session = Session()
            try:
                novel_menu = session.query(NovelMenu).filter_by(novel_id=novel_id, order=c["chapter"]).first()
                if novel_menu:
                    session.query(NovelMenu).filter_by(novel_id=novel_id, order=c["chapter"]).update({"name": c["name"], "address": c["address"],"drive_name": drive_name, "content": c["content"]})
                else:
                    session.add(NovelMenu(name=c["name"], order=c["chapter"], content=c["content"], drive_name=drive_name, address=c["address"], novel_id=novel_id))
                session.commit()
            finally:
                session.close()
    except Exception:
        print("异步切换书源 异常", traceback.print_exc())


# 切换书源
def switching_book_source_func(user, data, tasks):
    session = Session()
    try:
        # 查询小说是否存在
        novel = session.query(NovelList).filter(NovelList.id == data.novel_id).first()
        if not novel:
            return False, "没有该书籍信息"

        # 最新章
        last_chapter = session.query(NovelMenu).filter(NovelMenu.novel_id == novel.id, NovelMenu.order == data.chapter_id).first()
        if not last_chapter:
            return False, "该书籍没有该章节信息"

        # 查看驱动地址
        drive = session.query(BookSource).filter_by(id=data.drive_id).first()
        if not drive or not drive.address:
            return False, "没有该驱动或者驱动地址为空"

        # 后台添加任务  , , , start_chapter
        tasks.add_task(sbsf, novel_id=data.novel_id, drive_name=drive.drive_name, address=drive.address, start_chapter=last_chapter.order)

    except Exception:
        print("切换书源异常", traceback.format_exc())
        return False, "切换书源异常"

    finally:
        session.close()

    return True, "操作成功"


# 朗读书籍内容
def read_noall_content(book_id, chapter_order):
    session = Session()
    return_path = None
    try:
        # 查询书源
        cache = Cache.getInstance()
        # 获取书籍内容
        chapter_key = "novel_content_" + str(book_id) + "_" + str(chapter_order)
        result = cache.get(chapter_key)
        if result:
            content = json.loads(result)
            content = "\n".join(content["content"])
        else:
            find_content = session.query(NovelMenu).filter(NovelMenu.novel_id == book_id, NovelMenu.order == chapter_order).first()
            if not find_content:
                # 获取后一个章节
                find_content = session.query(NovelMenu).filter(NovelMenu.novel_id == book_id, NovelMenu.order >= chapter_order).order_by(NovelMenu.order.asc()).first()
                if not find_content:
                    return False, "章节不存在"
            content = find_content.content

        return_path = f"{book_id}/{chapter_order}" + "/{}.mp3"
        
        # 加载数据 
        root_path = os.getcwd()
        path = os.path.join(root_path, f"static/voices/novels/{return_path}")
        speaker_wav = os.path.join(root_path, "spearkers/girl.wav")
        params = {
            "path": path,
            "driver": "tts",
            "speaker": speaker_wav,
            "language": "zh-cn",
        }
        aigc_func("Voice", content, params)

    except Exception as e:
        print("朗读书籍内容 异常", traceback.print_exc())
        return False, e
    finally:
        session.close()

    return True, return_path

# 修改私密书籍
def update_private_func(user, book_id):
    session = Session()
    try:
        book = session.query(BookShelf).filter(BookShelf.user_id == user.id, BookShelf.novel_id == book_id).first()
        if not book:
            return False, "没有该书籍信息"
        book.private = 1 if book.private == 2 else 2
        session.commit()

        return True, '操作成功'
        
    except Exception as e:
        print("修改私密书籍 异常", traceback.print_exc())
        return False, e
    finally:
        session.close()